posts - 2,  comments - 9,  trackbacks - 0
公告
  2010年1月2日

  2010年已经到了,已经好久没写博客了,在新年的起始该在园子里说点东西了。

  前段时间给公司做了一个类似QQ的Asp.net在线聊天程序,与服务器之间的通讯是通过前台页面的定时器到服务器上的临时消息目录中取得相关信息来实现的,消息结构XML,为了避免对服务器造成太大的压力就只开了一个定时器,也没敢多开,程序完成后由于测试条件限制只在少的可怜的几台机器上测试了一下,效果还算可以吧,目前能实现发送文字,图片,文件查看历史记录,网络硬盘等基本功能,由于聊天窗口是嵌套在公司主框架里面的所以得实现聊天主窗体和聊天窗体以及一些其他窗体之间指针的引用问题,避免某个聊天窗口被打开多次,或者聊天窗口而主窗口也不知道的问题,下面介绍下程序中用javascript实现的窗口机制:

  看其他人的程序是很困难的,所以先介绍下例子实现的效果:首先创建一个MainFrm.htm窗体(启动窗体) ,用它打开a.htm窗口,a.htm窗体只能打开一个,在a.htm窗体中可以打开b.htm和c.htm,当然b.htm和c.htm窗口也只能打开一个,然后当MainFrm.htm关闭时让a.htm,b.hml和c.htm也跟着关闭,或者a.htm关闭时让b.htm和c.htm也关闭

     1、MainFrm窗体

   为了方便应用,我对数组方法进行扩展,添加了add,remove,clear三个方法

代码
if (!Array.prototype.add) {
    Array.prototype.add 
= function() {
        var startLength 
= this.length;
        
for (var i = 0; i < arguments.length; i++)
            
this[startLength + i] = arguments[i];
        
return this.length;
    };
}
if (!Array.prototype.remove) {
    Array.prototype.remove 
= function(index) {
        
if(index>=0 && index<this.length)
        {
            
this.splice(index,1);
        }
    };
}

if (!Array.prototype.clear) {
    Array.prototype.clear 
= function() {
        
this.splice(0,this.length);
    };

   定义一个存放注册窗口的缓存数组

//已注册的窗口数组
var g_oWindowArray=new Array();

  为子窗体提供注册函数,并定义一个删除注册函数通过窗体ID找到注册窗体的函数

代码
//注册窗口
function RegisterWindow()
{
    
for (var i = 0; i < arguments.length; i++)
    {
        var oWin
=arguments[i];
        g_oWindowArray.add(oWin);
    }
}

//删除注册窗口
function UnregisterWindow()
{
    
//从数组中删除
    for (var i = 0; i < arguments.length; i++)
    {
        var tmpOWin 
= arguments[i];
        
for(var i=0;i<g_oWindowArray.length;i++)
        {
            
if(g_oWindowArray[i]==tmpOWin)
            {
                tmpOWin.close();
                g_oWindowArray.remove(i);
            }
        }
    }
}

//通过用户ID找到注册过的窗口对象
function FindRegisterWindowById(strID)
{
    
for(var i=0;i<g_oWindowArray.length;i++)
    {
        var oWin
=g_oWindowArray[i];
        
if(oWin.GetFrmID()==strID)
        {
            
return oWin;
        }
    }
    
return null;
}

  每个子窗体都必须实现的接口函数,这里只提供一个返回窗体标示ID的函数和取得MainFrm窗体指针的函数

//返回窗体惟一标志ID
function GetFrmID()
{
    
return "";
}
//取得主窗体指针
function GetOpener()
{
  
return window;
}

  当主窗体关闭时,关闭所有子窗体,主窗体关闭时执行的函数

代码
//窗体关闭时候执行的函数
window.onunload = function()
{
    
try
    {
        
for(var i=0;i<g_oWindowArray.length;i++)
        {
            var oWin 
= g_oWindowArray[i];
            
if(oWin)
                oWin.parent.close();
        }
    }
    
catch(e)
    {
        alert(
"窗口注销时出错!"+e.message+"\n\n 错误说明 : "+e.description + e.message);
        window.close();
    }
}

  打开a.htm

代码
//打开窗口
function ShowMain()
{
    var oWin 
= FindRegisterWindowById("aFrm");
    
    
if(oWin==null)
    {
        var strURL
='a.htm';
  
        var oWin 
= window.open(strURL);
    }
    
else
        oWin.focus();
        
    
return oWin;
}

  MainFrm的Html代码

<body>
  
<input type="button" value="打开窗体" style="height:50px;width:100px" onclick="ShowMain();"/>
</body>


  2、a.htm窗体 

 

 

  a.htm中首先要实现MainFrm窗口定义的接口,由于要实现能关闭b.htm和c.htm所以包括了一个数组的add扩展方法(没有将数组扩展写成js文件)和一个窗口关闭时执行的方法,当然的包括窗口的注册了,代码不一一介绍,页面整体代码如下:

代码
<html>
<script>
//数组方法扩展
if (!Array.prototype.add) { 
    Array.prototype.add 
= function() { 
        var startLength 
= this.length; 
        
for (var i = 0; i < arguments.length; i++
            
this[startLength + i] = arguments[i]; 
        
return this.length; 
    }; 
}
var winOpener 
= window.opener.GetOpener();
var g_ChildWinArr 
= new Array();
/////////////////////////////接口定义方法部分////////////////////////////////////////
    
//取得当前窗体ID
function GetFrmID()
{
    
return "aFrm";
}

//取得主窗体指针
function GetOpener()
{
  
return winOpener;
}

//////////////////////////////////////////////////////////////////////////////////////

//关闭窗口时候取消注册
window.onunload = function()
{
   
try
   {
       winOpener.UnregisterWindow(window);
       
       
for(var i=0;i-g_ChildWinArr.length;i++)
       {
         var oWin 
= winOpener.FindRegisterWindowById(g_ChildWinArr[i]);      
         
if(oWin!=null)
         {
            winOpener.UnregisterWindow(oWin);
         }
      }
   }
   
catch(e)
   {}
}

//向主页面注册窗体对象 
winOpener.RegisterWindow(window);

function ShowOneFrm(strURL,strName)
{
  
try
  {
    var oWin 
= winOpener.FindRegisterWindowById(strName);
          
    
if(oWin==null)
    {
       oWin 
= window.open(strURL);
       g_ChildWinArr.add(strName);
    }
    
else
       oWin.focus();
   }
   
catch(e)
   {
      alert(strName 
+"窗口消息注册过程中出错!"+e.message+"\n\n 错误说明 : "+e.description + e.message);
   }
}

</script>
<body>
  
<input type="button" value="打开a窗体" style="height:25px;width:50px" onclick="ShowOneFrm('c.htm','cFrm');"/><br/>
  
<input type="button" value="打开b窗体" style="height:25px;width:50px" onclick="ShowOneFrm('b.htm','bFrm');"/>
</body>

</html>

  3、b.htm和c.htm窗体

  这两个窗体的不用实现再关闭它的子窗体了所以不包含一些数组扩展函数和窗体关闭执行的函数等,只实现窗口注册和接口定义就行了

   b.htm代码如下:

代码
<html>
<script>
var winOpener 
= window.opener.GetOpener();
/////////////////////////////接口定义方法部分////////////////////////////////////////
    
//取得当前窗体ID
function GetFrmID()
{
    
return "bFrm";
}

//取得主窗体指针
function GetOpener()
{
  
return winOpener;
}

//向主页面注册窗体对象 
winOpener.RegisterWindow(window);

//注销窗体
window.onunload = function()
{
   
try
   {
       winOpener.UnregisterWindow(window);
   }
   
catch(e)
   {}
}

</script>
<body>
<p>我是B窗体</p>

</body>

</html>

  c.htm代码如下:

代码
<html>
<script>
var winOpener 
= window.opener.GetOpener();
/////////////////////////////接口定义方法部分////////////////////////////////////////
    
//取得当前窗体ID
function GetFrmID()
{
    
return "cFrm";
}

//取得主窗体指针
function GetOpener()
{
  
return winOpener;
}

//向主页面注册窗体对象 
winOpener.RegisterWindow(window);

//注销窗体
window.onunload = function()
{
   
try
   {
       winOpener.UnregisterWindow(window);
   }
   
catch(e)
   {}
}

</script>
<body>
<p>我是A窗体</p>

</body>

</html>


   好了以上就是javascript 实现窗口注册的机制了,如果用于Web聊天的话就要多定义几个接口方法了,比如说:GetChatUserID()(获得当前聊天用户ID)、OnMessage(strMessageID,strMessageXML)(聊天窗口获得消息后的事件)等,不过我感觉要是网速过慢或者登录人过多的时候有可能会出现窗口的注册出现问题,这些就只能通过对错误的捕捉然后重新打开来实现了。

 

附件:

MainFrm窗体代码

a.htm

b.htm

c.htm

 

 

posted @ 2010-01-02 17:37 wtf_net110 阅读(2477) 评论(8) 编辑
  2009年10月15日

引言:
      最近给客户做一个B/S架构的证券交易大屏幕软件,其中用到对证券指数的走势以及成交量的图形绘制,由于客户要求图形的清晰而且要做成于原来的老系统一样的图形显示效果,就试着用ChartDirector进行图形绘制,第一次用看着文档帮助是挺方便的,CTrl+C、CTrl+V就画出一个走势图,看着和客户给的效果图差不多,挺简单的,可到了想调整细节的时候却发现怎么都达不到想要的结果,然后到网上搜呀搜发现都是一些从帮助文档中拷贝出来的东西,而且很少有C#的,最终还是在VS智能提示的情况下凭着金山词霸的帮助将那一个个参数给试了出来,最终得到了想要的效果,好了废话不多说,下面说个人绘制的走势图主要代码(有所修改)

代码:

using ChartDirector;

     //生成图形数据信息,iWidth:与画布有关的宽度,iHeight:与画布有关的高度,dlChartData:Y轴数据
        private XYChart GetTrendChart( int iWidth, int iHeight,double[] dlChartData)
        {
            try
            {
                  /***********此处代码仅供参考,个人取得画第一个点时从Y轴的中心开始,并且对应证券开盘时间******************/
                double dlLin = dlChartData[0];
                double dlMax = dlChartData[0];
                //X轴数据
                string[] XData = new string[2880];
                for (int i = 0; i < dlChartData.Length; i++)
                {
                    XData[i] = " ";

                    //取最小数据
                    if (dlChartData[i] < dlLin)
                        dlLin = dlChartData[i];

                    //取最大数据
                    if (dlChartData[i] > dlMax)
                        dlMax = dlChartData[i];
                }

                //继续给未赋值的数据赋值
                for (int i = dlChartData.Length; i < 2880; i++)
                {
                    XData[i] = " ";
                }

                //最小数、最大数相对于第一个点的浮动大小
                double dlFir = Math.Abs(m_KPNum - dlLin);
                double dlSec = Math.Abs(m_KPNum - dlMax);
                double dlFloat = dlFir > dlSec ? dlFir : dlSec;

            /**********************************************/

            /*****************开始画图***********************/

                // 创建图形对象
                XYChart c = new XYChart(iWidth, iHeight);

                //设置Y轴
                double dMin = Math.Round(m_KPNum - dlFloat, 2);
                double dMax = Math.Round(m_KPNum + dlFloat, 2);
              
                if ((dMax - dMin) < dlChartData[0] * 0.5)
                {
                    dMax = Math.Round(dlChartData[0] + dlChartData[0] * 0.5,2);
                    dMin = Math.Round(dlChartData[0] - dlChartData[0] * 0.5,2);
                }
               
                  //设置Y轴的取值范围
                c.yAxis().setDateScale(dMin, dMax);

                  //设置Y轴要显示的网格线的个数为4
                c.yAxis().setLinearScale(dMin, dMax, (dMax - dMin) / 4);

                 //c.yAxis().setLabel();Y轴设置过Label后就不能自动生成曲线图了,需要自己去添加线层
                //c.yAxis().setLabelGap(10);//设置Y轴标签之间的缝隙
                //c.yAxis().setLabelStep((int)(dMax-dMin)/10);//设置Y轴标签数组的显示跨度
                //c.yAxis().setLabelFormat("{value}%");//格式化标签显示内容
                ////设置网格上边和标题下边的区域大小为(50, 30),字横向排列,字体为宋体,大小为9  
                //c.addLegend(50, 30, false, "Arial Bold", 9).setBackground(Chart.Transparent);  

              
                //设置与Y轴相关的颜色,其中最后一个参数为设置Y轴伸出坐标的小头的颜色,一般不想要的话就设置成画布的背景色
                c.yAxis().setColors(0xff0000, 0xff0000, 0xff0000, 0);
                //设置Y轴标签样式
                c.yAxis().setLabelStyle("simhei.ttf", 8, 0xFFFFFF);

                //设置Y轴标签的颜色(前两个和最后一个颜色各自相同,中间一个为白色)
                c.yAxis().setMultiFormat(Chart.SelectItemFilter(0), "<*color=23ff45*> {value}");
                c.yAxis().setMultiFormat(Chart.SelectItemFilter(1), "<*color=23ff45*> {value}");
                c.yAxis().setMultiFormat(Chart.SelectItemFilter(2), "<*color=FFffFF*> {value}");
                c.yAxis().setMultiFormat(Chart.SelectItemFilter(3), "<*color=ff2345*> {value}");
                c.yAxis().setMultiFormat(Chart.SelectItemFilter(4), "<*color=ff2345*> {value}");

                //设置X轴
                //为了实现X轴上隔行变实线的效果,添加了几个标记
                c.xAxis().addMark(720,0xff0000);//隔行实线
                c.xAxis().addMark(1440, 0xff0000);//隔行实线
                c.xAxis().addMark(2160, 0xff0000);//隔行实线

                c.xAxis().setColors(0xff0000, 0xff0000, 0xff0000, 0);
                c.xAxis().setLabelStyle("simhei.ttf", 5, 0xFFFFFF);
                c.xAxis().setLabels(XData);
                c.xAxis().setLabelStep(360
                //设置标题
                c.addTitle(Chart.Top, "上证指数", "Arial", 7.5, 0xffffff, 0x31319c);
       

                //绘制曲线图所需的数据
                c.addLineLayer(dlChartData,0xffffff);

                //设置背景色为白色 横坐标和纵坐标的网格线颜色,其中参数三和参数四为画布的大小,参数八和参数九为设置网格线为虚线(这里需要的为一个枚举变量)
                c.setPlotArea(47, 18, iWidth - 50, iHeight - 23, 0, -1, 0xff0000, c.dashLineColor(0xff0000, Chart.DotLine), c.dashLineColor(0xff0000, Chart.DotLine));

                //设置背景
                c.setBackground(0);      

                return c;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

好了这个就是用ChartDirector实现一个虚线的网格线,并且隔行变实线,Y轴的标签显示不同的颜色,X轴显示的时间为正常的证券交易时间,曲线图为相应时间对应的数据(在前面注释部分提过)的图形,对于ChartDirector画图需要掌握它画图的原理,就能画出想要的图形对应的坐标标签,以下为提供的一些意见(仅供参考):
      1、准备的Y轴的数据数组和X轴的标签数组建议相对应,这样才能确定在坐标轴上的某个点的位置是正确的位置
      2、ChartDirector画出的图形的起始位置是从X轴的原点开始,如果想要实现从X轴的某个点开始的话需要在X轴标签数组的前部分补空,在Y轴的数据数组相应的前部分补上Y轴的最小坐标(但会出现斜线上升的情况,这个就不太理想了)。
      3、对于X轴图形的结束位置,需要的话要在数据数组后面部分补上相应的空值,这样就能使图形不至于顶到坐标轴的末尾。
      4、X轴的标签数组长度可以大于Y轴,Y轴数据数组长度最好不要大于X轴,因为这样图形就会显示不全。
      5、设置Y轴的标签数据后,就不会自动生成图形了,需要自己添加图形层。
      6、合理运用 c.xAxis().setLabelStep()这个方法。
  图形结果:

      

posted @ 2009-10-15 23:13 wtf_net110 阅读(607) 评论(1) 编辑